package com.appspot.moviesessions.provider;

import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.http.impl.client.DefaultHttpClient;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.util.Log;

import com.appspot.moviesessions.EventListener;
import com.appspot.moviesessions.EventPublisher;
import com.appspot.moviesessions.EventPublisherImpl;

public class MovieSessionContentProvider extends ContentProvider {

	private DatabaseFactoryImpl factory;
	private MovieServiceImpl movieService;
	private ExecutorService executorService = Executors.newCachedThreadPool();
	private EventPublisher eventPublisher;

	private FileSystemPosterCache posterCache;
	public static final String TAG = "SessionProvider";

	@Override
	public boolean onCreate() {
		Log.v(TAG, "MovieSessionContentProvider onCreate");

		// sessionDataSource = new HTTPSessionDataSource(new
		// DefaultHttpClient());
		posterCache = new FileSystemPosterCache(new HTTPSessionDataSource(
				new DefaultHttpClient()), new FileFactoryImpl(getContext()
				.getCacheDir()));
		eventPublisher = new EventPublisherImpl();
		eventPublisher.register(refreshDataListener());
		eventPublisher.register(new EventListener<DataRefreshedEvent>() {
			@Override
			public void onEvent(DataRefreshedEvent event) {
				getContext().getContentResolver().notifyChange(
						MovieSession.CONTENT_URI, null);

			}
		});
		final UriMapping uriMapping = new UriMappingImpl(new UriMatcher(
				UriMatcher.NO_MATCH));

		SQLiteOpenHelper sqlOpenHelper = new SQLiteOpenHelper(getContext(),
				MovieSession.DATABASE_NAME, null, MovieSession.DATABASE_VERSION) {

			@Override
			public void onUpgrade(SQLiteDatabase db, int oldVersion,
					int newVersion) {
				Log.v(TAG, "upgrade database");
				new DatabaseFactoryImpl(new SQLLiteDatabaseAdapter(db),
						eventPublisher, oldVersion, newVersion);
				// movieService = new MovieServiceImpl(factory, uriMapping);
			}

			@Override
			public void onCreate(SQLiteDatabase db) {
				Log.v(TAG, "create database");
				new DatabaseFactoryImpl(new SQLLiteDatabaseAdapter(db),
						eventPublisher);
				// movieService = new MovieServiceImpl(factory, uriMapping);

			}

		};

		factory = new DatabaseFactoryImpl(new DatabaseAdapter(sqlOpenHelper,
				eventPublisher));
		movieService = new MovieServiceImpl(factory, uriMapping);

		return true;
	}

	private EventListener<DatabaseCreatedEvent> refreshDataListener() {
		return new EventListener<DatabaseCreatedEvent>() {

			@Override
			public void onEvent(final DatabaseCreatedEvent event) {
				Log.v(TAG, "Tables Created");
				executorService.execute(new FetchSessionDataTask(
						new HTTPSessionDataSource(new DefaultHttpClient()),
						new XMLSessionDataHandler(eventPublisher,
								new ContentValuesFactory() {
									@Override
									public ContentValues create() {
										return new ContentValues();
									}
								}, posterCache)));
			}
		};

	}

	public ExecutorService getExecutorService() {

		return executorService;
	}

	public void setExecutorService(ExecutorService executorService) {
		this.executorService = executorService;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String where,
			String[] whereArgs, String sortOrder) {
		String logArgs = (whereArgs == null) ? "" : Arrays.toString(whereArgs);
		Log.v(TAG, String.format("inside query: uri -> %s, whereArgs -> %s",
				uri, logArgs));
		Cursor cursor = movieService.query(uri, projection, where, whereArgs,
				sortOrder);
		cursor.setNotificationUri(getContext().getContentResolver(), uri);
		return cursor;
	}

	@Override
	public ParcelFileDescriptor openFile(Uri uri, String mode)
			throws FileNotFoundException {
		return ParcelFileDescriptor.open(
				posterCache.get(ContentUris.parseId(uri)),
				ParcelFileDescriptor.MODE_READ_ONLY);
	}

	@Override
	public int delete(Uri uri, String where, String[] whereArgs) {
		throw new UnsupportedOperationException("Not yet implemented");
	}

	@Override
	public String getType(Uri uri) {
		throw new UnsupportedOperationException("Not yet implemented");
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		throw new UnsupportedOperationException("Not yet implemented");
	}

	@Override
	public int update(Uri uri, ContentValues values, String where,
			String[] whereArgs) {
		throw new UnsupportedOperationException("Not yet implemented");
	}

	private static class SQLLiteDatabaseAdapter implements Database {
		private SQLiteDatabase db;

		public SQLLiteDatabaseAdapter(SQLiteDatabase db) {
			super();
			this.db = db;
		}

		@Override
		public Cursor query(QuerySpecification with) {
			throw new UnsupportedOperationException();
		}

		@Override
		public void execSQL(String sql) {
			db.execSQL(sql);
		}

		@Override
		public long insert(String table, ContentValues values) {
			throw new UnsupportedOperationException();
		}

		@Override
		public Cursor rawQuery(String query, String[] selectionArgs) {
			throw new UnsupportedOperationException();
		}

	}
}
